﻿using System;

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.ComponentModel;


namespace Eniux.Windows.Dock
{
    /// <summary>
    /// 灰度图片
    /// </summary>
  public class GreyableImage : Image
  {
      #region 变量

      // these are holding references to original and greyscale ImageSources
      private ImageSource _sourceC, _sourceG;
      // these are holding original and greyscale opacity masks
      private Brush _opacityMaskC, _opacityMaskG;
      
      #endregion

      #region 构造

      /// <summary>
      /// 静态构造
      /// </summary>
      static GreyableImage()
      {
          DefaultStyleKeyProperty.OverrideMetadata(typeof(GreyableImage), new FrameworkPropertyMetadata(typeof(GreyableImage)));
      } 

      #endregion

      #region 重写

      protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
      {
          if (e.Property.Name.Equals("IsEnabled"))
          {
              if ((e.NewValue as bool?) == false)
              {
                  Source = _sourceG;
                  OpacityMask = _opacityMaskG;
              }
              else if ((e.NewValue as bool?) == true)
              {
                  Source = _sourceC;
                  OpacityMask = _opacityMaskC;
              }
          }
          else if (e.Property.Name.Equals("Source") &&
                   !object.ReferenceEquals(Source, _sourceC) &&
                   !object.ReferenceEquals(Source, _sourceG))  // only recache Source if it's the new one from outside
          {
              SetSources();
          }
          else if (e.Property.Name.Equals("OpacityMask") &&
                   !object.ReferenceEquals(OpacityMask, _opacityMaskC) &&
                   !object.ReferenceEquals(OpacityMask, _opacityMaskG)) // only recache opacityMask if it's the new one from outside
          {
              _opacityMaskC = OpacityMask;
          }

          base.OnPropertyChanged(e);
      }
      
      #endregion

      #region 方法

      private void SetSources()
      {
          // in case greyscale image cannot be created set greyscale source to original Source first
          _sourceG = _sourceC = Source;

          // create Opacity Mask for greyscale image as FormatConvertedBitmap does not keep transparency info
          _opacityMaskG = new ImageBrush(_sourceC);
          _opacityMaskG.Opacity = 0.6;

          try
          {
              // get the string Uri for the original image source first
              String stringUri = TypeDescriptor.GetConverter(Source).ConvertTo(Source, typeof(string)) as string;
              Uri uri = null;
              // try to resolve it as an absolute Uri (if it is relative and used it as is
              // it is likely to point in a wrong direction)
              if (!Uri.TryCreate(stringUri, UriKind.Absolute, out uri))
              {
                  // it seems that the Uri is relative, at this stage we can only assume that
                  // the image requested is in the same assembly as this oblect,
                  // so we modify the string Uri to make it absolute ...
                  stringUri = "pack://application:,,,/" + stringUri.TrimStart(new char[2] { System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar });

                  // ... and try to resolve again
                  uri = new Uri(stringUri);
              }

              // create and cache greyscale ImageSource
              _sourceG = new FormatConvertedBitmap(new BitmapImage(uri), PixelFormats.Gray8, null, 0);
          }
          catch (Exception e)
          {
              System.Diagnostics.Debug.Fail("The Image used cannot be greyed out.",
                                            "Use BitmapImage or URI as a Source in order to allow greyscaling. Make sure the absolute Uri is used as relative Uri may sometimes resolve incorrectly.\n\nException: " + e.Message);
          }
      }
      
      #endregion
  }
}
